"""
SSL连接辅助工具
提供统一的SSL上下文创建和IMAP/SMTP连接方法
"""
import ssl
import imaplib
import smtplib
from api.utils.logger import get_logger

logger = get_logger("ssl_helper")


def create_ssl_context(strict_mode: bool = True) -> ssl.SSLContext:
    """
    创建SSL上下文，支持严格和宽松两种模式
    
    Args:
        strict_mode: 是否使用严格的证书验证（默认True）
        
    Returns:
        ssl.SSLContext: 配置好的SSL上下文
    """
    context = ssl.create_default_context()
    
    if strict_mode:
        # 严格模式：完整的证书验证
        try:
            import certifi
            context.load_verify_locations(cafile=certifi.where())
        except ImportError:
            context.load_default_certs()
        except Exception as e:
            context.load_default_certs()
        
        context.check_hostname = True
        context.verify_mode = ssl.CERT_REQUIRED
        context.minimum_version = ssl.TLSVersion.TLSv1_2
        
        # 兼容较老的服务器
        try:
            context.set_ciphers('DEFAULT@SECLEVEL=1')
        except Exception as e:
            pass
    else:
        # 宽松模式：禁用证书验证（仅在必要时使用）
        context.check_hostname = False
        context.verify_mode = ssl.CERT_NONE
        context.minimum_version = ssl.TLSVersion.TLSv1_2
    
    return context


def create_imap_connection(server: str, port: int, use_ssl: bool = True, timeout: int = 30):
    """
    创建IMAP连接，自动处理SSL证书验证问题和连接重置问题
    
    Args:
        server: IMAP服务器地址
        port: IMAP端口
        use_ssl: 是否使用SSL（默认True）
        timeout: 连接超时时间（秒）
        
    Returns:
        imaplib.IMAP4 or imaplib.IMAP4_SSL: IMAP连接对象
        
    Raises:
        Exception: 连接失败时抛出异常
    """
    import time
    import socket
    
    if not use_ssl:
        return imaplib.IMAP4(server, port, timeout=timeout)
    
    # 连接重试配置：只重试1次
    max_retries = 2  # 总共尝试2次（初次 + 重试1次）
    retry_delay = 3  # 秒
    last_error = None
    
    for attempt in range(max_retries):
        try:
            # 先尝试严格模式
            try:
                context = create_ssl_context(strict_mode=True)
                imap = imaplib.IMAP4_SSL(server, port, ssl_context=context, timeout=timeout)
                return imap
            except ssl.SSLError as e:
                if "certificate verify failed" in str(e).lower():
                    # 降级到宽松模式
                    context = create_ssl_context(strict_mode=False)
                    imap = imaplib.IMAP4_SSL(server, port, ssl_context=context, timeout=timeout)
                    return imap
                else:
                    # 其他SSL错误也尝试重试
                    raise
        
        except (ConnectionResetError, ConnectionRefusedError, ConnectionError,
                socket.error, OSError) as e:
            # 连接被重置或拒绝，可以重试
            last_error = e
            
            if attempt < max_retries - 1:
                # 还有1次重试机会，等待后重试（不输出日志）
                time.sleep(retry_delay)
                continue
            else:
                # 已达最大重试次数，直接抛出（不输出错误日志）
                raise
        
        except Exception as e:
            # 其他异常直接抛出（不输出错误日志）
            raise
    
    # 如果循环结束还没有返回，抛出最后的错误
    if last_error:
        raise last_error


def create_smtp_connection(server: str, port: int, use_ssl: bool = True, timeout: int = 30):
    """
    创建SMTP连接，自动处理SSL证书验证问题
    
    Args:
        server: SMTP服务器地址
        port: SMTP端口
        use_ssl: 是否使用SSL（默认True）
        timeout: 连接超时时间（秒）
        
    Returns:
        smtplib.SMTP or smtplib.SMTP_SSL: SMTP连接对象
        
    Raises:
        Exception: 连接失败时抛出异常
    """
    if not use_ssl:
        return smtplib.SMTP(server, port, timeout=timeout)
    
    # 先尝试严格模式
    try:
        context = create_ssl_context(strict_mode=True)
        smtp = smtplib.SMTP_SSL(server, port, context=context, timeout=timeout)
        return smtp
    except ssl.SSLError as e:
        if "certificate verify failed" in str(e).lower():
            # 降级到宽松模式
            try:
                context = create_ssl_context(strict_mode=False)
                smtp = smtplib.SMTP_SSL(server, port, context=context, timeout=timeout)
                return smtp
            except Exception as fallback_error:
                logger.error(f"宽松模式连接也失败: {fallback_error}")
                raise
        else:
            # 其他SSL错误直接抛出
            raise

